from colorama import init#, Fore, Back, Style
init()  # autoreset=True tiene conflictos con el autcompletar de cmd
from termcolor import colored
import multiprocessing
import cmd
import re
import sys
import signal
signal.signal(signal.SIGINT, lambda s,f:exit(0))

def get_color(filters, line):
    color = None
    for f in filters.values():
        if f(line):
            color = f.color
    return color

def read_file(filename, positives, negatives, foregrounds, lock):
    fd = open(filename, 'r')
    fd.seek(0, 2)
    while True:
        lock.acquire()
        line = fd.readline()
        if line:
            fgcolor = get_color(foregrounds, line)
            allow = any(f(line) for f in positives.values())
            deny = any(f(line) for f in negatives.values())
            if (not positives and not negatives) or (positives and allow) or (negatives and not deny):
                sys.stdout.write(colored(line, fgcolor))
        lock.release()

class Filter(object):

    def __init__(self, pattern, color=None):
        self.pattern = pattern
        self.searcher = re.compile(pattern)
        self.color = color

    def __call__(self, line):
        return self.searcher.search(line)

class BeeCmd(cmd.Cmd):

    prompt = ''


    def valid_command(self):
        if not self.locked:
            self.lock.acquire()

    def do_reset(self, line):
        self.valid_command()
        self.positives.clear()
        self.negatives.clear()
        print colored(u"All filters cleared", 'white', 'on_blue')

    def do_show(self, line):
        self.valid_command()
        if self.negatives:
            self.negatives.clear()
        f = Filter(line)
        self.positives[line] = f

    def do_noshow(self, line):
        self.valid_command()
        if line in self.positives.keys():
            del self.positives[line]
        else:
            print colored(u"Can't noshow, not in SHOW mode", 'white', 'on_red')

    def complete_noshow(self, text, line, begidx, endidx):
        self.valid_command()
        return [x for x in self.positives.keys() if x.startswith(text)]

    def do_hide(self, line):
        self.valid_command()
        if self.positives:
            self.positives.clear()
        f = Filter(line)
        self.negatives[line] = f

    def do_nohide(self, line):
        self.valid_command()
        if line in self.negatives.keys():
            del self.negatives[line]
        else:
            print colored(u"Can't nohide, not in HIDE mode", 'white', 'on_red')

    def complete_nohide(self, text, line, begidx, endidx):
        self.valid_command()
        return [x for x in self.negatives.keys() if x.startswith(text)]

    def do_color(self, args):
        self.valid_command()
        regex, color = args.split()
        f = Filter(regex, color=color)
        self.foregrounds[regex] = f

    def do_EOF(self, line):
        return True

    def emptyline(self):
        if self.locked:
            self.locked = False
            self.lock.release()
        else:
            self.locked = True
            self.lock.acquire()

    def default(self, line):
        self.default_called = True
        print colored(u"Incorrect command: %s" % line, 'white', 'on_red')

    def postcmd(self, stop, line):
        if not self.default_called:
            self.locked = False
            self.lock.release()
        else:
            self.default_called = False
        return stop

if __name__ == '__main__':
    filename = sys.argv[1]
    manager = multiprocessing.Manager()
    positives = manager.dict()
    negatives = manager.dict()
    foregrounds = manager.dict()
    lock = multiprocessing.Lock()

    p = multiprocessing.Process(target=read_file, args=(filename, positives,
                                                        negatives, foregrounds,
                                                        lock))
    p.start()
    beecmd = BeeCmd()
    beecmd.positives = positives
    beecmd.negatives = negatives
    beecmd.foregrounds = foregrounds
    beecmd.lock = lock
    beecmd.locked = False
    beecmd.default_called = False
    beecmd.cmdloop()
